package com.edfeff.bio.http;

import java.io.IOException;
import java.io.OutputStream;

import static com.edfeff.bio.http.Constants.*;

public class OutputBuffer {
    private byte[] buf;
    private int pos;
    private Response response;
    private OutputStream outputStream;

    public OutputBuffer(Response response) {
        this.response = response;
        buf = new byte[48 * 1024];
        pos = 0;
    }

    public void setOutputStream(OutputStream outputStream) {
        this.outputStream = outputStream;
    }

    public void endRequest() throws IOException {
        writeResponse();
        this.outputStream.flush();
    }

    /**
     * <pre>
     *        Response      = Status-Line               ; Section 6.1
     *                        *(( general-header        ; Section 4.5
     *                         | response-header        ; Section 6.2
     *                         | entity-header ) CRLF)  ; Section 7.1
     *                        CRLF
     *                        [ message-body ]          ; Section 7.2
     *
     *
     * Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
     *
     * </pre>
     */
    private void writeResponse() throws IOException {
        //1 写响应行
        writeStatusLine();
        //2 写响应头
        writeHeaders();
        writeCRLF();

        //3 写响应体
        if (response.getBody() != null && response.getBody().length > 0) {
            writeBody();
        }
        outputStream.write(buf, 0, pos);
        outputStream.flush();
    }

    private void writeBody() {
        byte[] body = response.getBody();
        writeBytes(body);
    }

    private void writeHeaders() {
        for (Header header : response.getHeaders()) {
            String headerLine = String.format("%s: %s", header.getName(), header.getValue());
            writeString(headerLine);
            writeCRLF();
        }
    }

    private void writeString(String msg) {
        byte[] bytes = msg.getBytes(charset);
        writeBytes(bytes);
    }

    private void writeBytes(byte[] bytes) {
        System.arraycopy(bytes, 0, buf, pos, bytes.length);
        pos += bytes.length;
    }

    private void writeCRLF() {
        buf[pos++] = CR;
        buf[pos++] = LF;
    }

    /**
     * <pre>
     *      Status-Code    =
     *             "100"  ; Section 10.1.1: Continue
     *             ...
     * </pre>
     *
     * @throws IOException
     */
    private void writeStatusLine() throws IOException {
        String responseLine = String.format("HTTP/1.1 %d %s", response.getStatus(), STATUS_CODE_MAP.get(response.getStatus()));
        writeString(responseLine);
        writeCRLF();
    }
}
